package com.xu.cloud.common.conditional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;

/**
 * @author xuguan
 * @since 2023/11/24
 */
public class OnAnnotationStatementCondition implements Condition {

    public static final Logger log = LoggerFactory.getLogger(OnAnnotationStatementCondition.class);

    @SuppressWarnings({"unchecked", "OptionalGetWithoutIsPresent"})
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
        // 获取ConditionalOnAnnotationStatement注解
        MergedAnnotation<ConditionalOnAnnotationStatement> annotation = metadata
                .getAnnotations()
                .get(ConditionalOnAnnotationStatement.class);

        boolean match = false;

        if (annotation.isPresent()) {
            // 获取ConditionalOnAnnotationStatement注解的value属性
            Class<? extends Annotation>[] value = (Class<? extends Annotation>[]) annotation.getValue("value").get();
            Assert.notEmpty(value, "The value attribute of @ConditionalOnAnnotation must not be empty");

            for (Class<? extends Annotation> anno : value) {
                ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
                Assert.notNull(beanFactory, "The beanFactory must not be null");
                int size = beanFactory
                        .getBeansWithAnnotation(anno)
                        .size();
                if (size == 0) {
                    log.info("The annotation {} is not declared", anno.getName());
                    match = false;
                    break;
                }
                match = true;
            }
        }

        return match;
    }
}
